// 文件路径: user-module/src/main/java/org/x/user/service/impl/RegisterServiceImpl.java
package org.x.user.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import org.mindrot.jbcrypt.BCrypt;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.x.common.config.Result;
import org.x.user.dto.*;
import org.x.user.entity.SysUserEntity;
import org.x.user.mapper.SysUserMapper;
import org.x.user.service.RegisterService;

import java.io.IOException;
import java.util.Base64;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Service
public class RegisterServiceImpl implements RegisterService {

    @Autowired
    private SysUserMapper sysUserMapper;

    // 验证码存储（实际项目中应该使用Redis等缓存，这里用内存存储模拟）
    private static final ConcurrentHashMap<String, String> CODE_CACHE = new ConcurrentHashMap<>();

    // 最后发送时间记录
    private static final ConcurrentHashMap<String, Long> LAST_SEND_TIME = new ConcurrentHashMap<>();

    // 验证码有效期（毫秒）
    private static final long CODE_EXPIRE_TIME = TimeUnit.MINUTES.toMillis(5);

    // 发送间隔（毫秒）
    private static final long SEND_INTERVAL = TimeUnit.MINUTES.toMillis(1);

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result publicRegister(PublicRegisterDTO publicRegisterDTO) {
        // 1. 校验验证码
        String cachedCode = getCodeFromCache(publicRegisterDTO.getMobile());
        if (cachedCode == null || !cachedCode.equals(publicRegisterDTO.getCode())) {
            return Result.error(400,"验证码错误或已过期");
        }

        // 2. 检查手机号是否已注册
        if (isPhoneRegistered(publicRegisterDTO.getMobile())) {
            return Result.error(400,"该手机号已被注册");
        }

        // 3. 检查用户名是否已存在
        if (isUsernameExists(publicRegisterDTO.getUsername())) {
            return Result.error(400,"用户名已存在");
        }

        // 4. 创建用户
        SysUserEntity user = new SysUserEntity();
        user.setUsername(publicRegisterDTO.getUsername());
        user.setMobile(publicRegisterDTO.getMobile());
        user.setPassword(BCrypt.hashpw(publicRegisterDTO.getPassword(), BCrypt.gensalt()));
        user.setUserType("USER"); // 公众用户
        user.setStatus(true); // 默认启用
        user.setIsDelete(false);
        user.setCreatedBy("system");
        user.setUpdatedBy("system");
        user.setCreatedTime(new Date());
        user.setUpdatedTime(new Date());
        // 添加这一行来设置 real_name 字段
        user.setRealName(publicRegisterDTO.getUsername()); // 或者设置为其他合适的默认值
// 记录协议版本
        user.setRemark("agreement_version:" + "v1.0" + ",agreed_at:" + System.currentTimeMillis());

        sysUserMapper.insertSelective(user);

        // 5. 清除验证码
        removeCodeFromCache(publicRegisterDTO.getMobile());

        // 6. 自动登录
        StpUtil.login(user.getId());

        Result result = Result.ok();
        result.setMsg("注册成功");
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result lawyerRegister(LawyerRegisterDTO lawyerRegisterDTO) {
        // 1. 校验验证码
        String cachedCode = getCodeFromCache(lawyerRegisterDTO.getMobile());
        if (cachedCode == null || !cachedCode.equals(lawyerRegisterDTO.getCode())) {
            return Result.error(400,"验证码错误或已过期");
        }

        // 2. 检查手机号是否已注册
        if (isPhoneRegistered(lawyerRegisterDTO.getMobile())) {
            return Result.error(400,"该手机号已被注册");
        }

        // 3. 检查用户名是否已存在
        if (isUsernameExists(lawyerRegisterDTO.getUsername())) {
            return Result.error(400, "用户名已存在");
        }

        // 4. 检查执业证照片
        MultipartFile licensePhotoFile = lawyerRegisterDTO.getLicensePhoto();
        if (licensePhotoFile == null || licensePhotoFile.isEmpty()) {
            return Result.error(400, "请提供执业证照片");
        }

        // 5. 调用OCR服务识别证件信息（模拟）
        // 实际项目中应该调用OCR服务，这里简化处理
        boolean ocrSuccess = simulateOcrService(licensePhotoFile);

        if (!ocrSuccess) {
            return Result.error(400, "证件信息识别失败，请手动输入");
        }

        // 6. 自动填充证件信息（模拟）
        // 实际项目中OCR服务应该返回识别结果，这里简化处理
        autoFillLicenseInfo(lawyerRegisterDTO);

        // 7. 创建用户（律师用户需要审核，状态默认为禁用）
        SysUserEntity user = new SysUserEntity();
        user.setUsername(lawyerRegisterDTO.getUsername());
        user.setMobile(lawyerRegisterDTO.getMobile());
        user.setPassword(BCrypt.hashpw(lawyerRegisterDTO.getPassword(), BCrypt.gensalt()));
        user.setRealName(lawyerRegisterDTO.getRealName());
        user.setUserType("LAWYER"); // 律师用户
        user.setStatus(false); // 律师需要审核，默认禁用
        user.setIsDelete(false);
        user.setCreatedBy("system");
        user.setUpdatedBy("system");
        user.setCreatedTime(new Date());
        user.setUpdatedTime(new Date());
        // 记录协议版本
        user.setRemark("agreement_version:" + lawyerRegisterDTO.getAgreementVersion() +
                ",agreed_at:" + System.currentTimeMillis());

        sysUserMapper.insertSelective(user);

        // 8. 创建律师认证记录（简化处理，实际应该有专门的律师认证表）
        createLawyerCertificationRecord(user.getId(), lawyerRegisterDTO);

        // 9. 清除验证码
        removeCodeFromCache(lawyerRegisterDTO.getMobile());

        // 10. 通知管理员审核（简化处理，实际应该发送消息通知）
        notifyAdminForReview(user.getId());

        Result result = Result.ok();
        result.setMsg("注册申请已提交，请等待审核");
        return result;
    }

// 修改 simulateOcrService 方法以处理 MultipartFile
    /**
     * 模拟OCR服务
     * @param licensePhoto 执业证照片文件
     * @return 识别是否成功
     */
    private boolean simulateOcrService(MultipartFile licensePhoto) {
        // 当licensePhoto不为空时，提高成功率
        if (licensePhoto != null && !licensePhoto.isEmpty()) {
            // 90%概率成功，提高成功率
            return new Random().nextInt(100) < 90;
        }
        // 如果没有提供照片，50%概率成功
        return new Random().nextBoolean();
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result adminCreate(AdminCreateDTO adminCreateDTO) {
        // 1. 检查用户名是否已存在
        if (isUsernameExists(adminCreateDTO.getUsername())) {
            return Result.error(400,"用户名已存在");
        }

        // 2. 创建管理员用户
        SysUserEntity user = new SysUserEntity();
        BeanUtils.copyProperties(adminCreateDTO, user);
        // 生成初始密码
        String initialPassword = generateInitialPassword();
        user.setPassword(BCrypt.hashpw(initialPassword, BCrypt.gensalt()));
        user.setUserType("ADMIN"); // 管理员用户
        user.setStatus(true); // 管理员默认启用
        user.setIsDelete(false);
        user.setCreatedBy("system");
        user.setUpdatedBy("system");
        user.setCreatedTime(new Date());
        user.setUpdatedTime(new Date());

        sysUserMapper.insertSelective(user);

        // 3. 发送通知给新管理员（简化处理）
        sendNotificationToNewAdmin(user, initialPassword);

        Result result = Result.ok();
        result.setMsg("管理员创建成功，初始密码已发送");
        return result;
    }

    @Override
    public Result sendSmsCode(SmsSendDTO smsSendDTO) {
        // 检查发送频率
        Long lastSendTime = LAST_SEND_TIME.get(smsSendDTO.getMobile());
        long currentTime = System.currentTimeMillis();

        if (lastSendTime != null && currentTime - lastSendTime < SEND_INTERVAL) {
            return Result.error(429, "操作频繁，请稍后再试");
        }

        // 生成6位随机验证码
        String code = String.format("%06d", new Random().nextInt(999999));

        // 保存验证码和时间戳
        CODE_CACHE.put(smsSendDTO.getMobile(), code + ":" + currentTime);
        LAST_SEND_TIME.put(smsSendDTO.getMobile(), currentTime);

        // 模拟发送短信（实际项目中应调用短信服务）
        System.out.println("模拟发送短信验证码: " + code + " 到手机号: " + smsSendDTO.getMobile());

        Result result = Result.ok();
        result.setMsg("验证码已发送（模拟）");
        result.setData(code);
        return result;
    }

    @Override
    public Result checkPhone(PhoneCheckDTO phoneCheckDTO) {
        boolean isRegistered = isPhoneRegistered(phoneCheckDTO.getMobile());
        Result result = Result.ok();
        result.setData(!isRegistered); // true表示未注册，可以使用
        return result;
    }



    @Override
    public Result getAgreement() {
        // 模拟注册协议内容
        String agreement = "用户注册协议\n\n" +
                "1. 用户在使用本系统时，必须遵守相关法律法规\n" +
                "2. 用户需提供真实有效的个人信息\n" +
                "3. 用户不得利用本系统从事任何违法活动\n" +
                "4. 本系统有权根据业务需要修改服务条款\n" +
                "5. 用户注册即表示同意本协议所有条款";

        // 协议版本号
        String version = "v1.0.0";

        Result result = Result.ok();
        result.setData(agreement);
        result.setMsg(version);
        return result;
    }

    /**
     * 从缓存中获取验证码并检查是否过期
     * @param mobile 手机号
     * @return 验证码，如果过期或不存在返回null
     */
    private String getCodeFromCache(String mobile) {
        String cachedValue = CODE_CACHE.get(mobile);
        if (cachedValue == null) {
            return null;
        }

        String[] parts = cachedValue.split(":");
        if (parts.length != 2) {
            return null;
        }

        String code = parts[0];
        long timestamp;
        try {
            timestamp = Long.parseLong(parts[1]);
        } catch (NumberFormatException e) {
            return null;
        }

        // 检查是否过期
        if (System.currentTimeMillis() - timestamp > CODE_EXPIRE_TIME) {
            CODE_CACHE.remove(mobile);
            return null;
        }

        return code;
    }


    private String fileToBase64(MultipartFile file) {
        try {
            byte[] bytes = file.getBytes();
            return Base64.getEncoder().encodeToString(bytes);
        } catch (IOException e) {
            return null;
        }
    }
    /**
     * 从缓存中移除验证码
     * @param mobile 手机号
     */
    private void removeCodeFromCache(String mobile) {
        CODE_CACHE.remove(mobile);
        LAST_SEND_TIME.remove(mobile);
    }

    /**
     * 检查手机号是否已注册
     * @param mobile 手机号
     * @return 是否已注册
     */
    private boolean isPhoneRegistered(String mobile) {
        return sysUserMapper.selectOneByQuery(
                com.mybatisflex.core.query.QueryWrapper.create()
                        .eq("mobile", mobile)
        ) != null;
    }

    /**
     * 检查用户名是否已存在
     * @param username 用户名
     * @return 是否已存在
     */
    private boolean isUsernameExists(String username) {
        return sysUserMapper.selectOneByQuery(
                com.mybatisflex.core.query.QueryWrapper.create()
                        .eq("username", username)
        ) != null;
    }

    /**
     * 模拟OCR服务
     * @param licensePhoto 执业证照片URL
     * @return 识别是否成功
     */
    private boolean simulateOcrService(String licensePhoto) {
        // 当licensePhoto不为空时，提高成功率
        if (licensePhoto != null && !licensePhoto.isEmpty()) {
            // 80%概率成功
            return new Random().nextInt(100) < 80;
        }
        // 如果没有提供照片，50%概率成功
        return new Random().nextBoolean();
    }


    /**
     * 自动填充证件信息
     * @param lawyerRegisterDTO 律师注册信息
     */
    private void autoFillLicenseInfo(LawyerRegisterDTO lawyerRegisterDTO) {
        // 模拟自动填充，实际应该从OCR服务获取
        if (lawyerRegisterDTO.getLicenseNumber() == null || lawyerRegisterDTO.getLicenseNumber().isEmpty()) {
            // 如果OCR识别成功但没有填充执业证号，则使用默认值
            lawyerRegisterDTO.setLicenseNumber("OCR1234567890");
        }
    }

    /**
     * 创建律师认证记录
     * @param userId 用户ID
     * @param lawyerRegisterDTO 律师注册信息
     */
    private void createLawyerCertificationRecord(Long userId, LawyerRegisterDTO lawyerRegisterDTO) {
        // 简化处理，实际应该有专门的律师认证表
        System.out.println("创建律师认证记录: userId=" + userId +
                ", licenseNumber=" + lawyerRegisterDTO.getLicenseNumber() +
                ", status=PENDING");
    }

    /**
     * 通知管理员审核
     * @param userId 用户ID
     */
    private void notifyAdminForReview(Long userId) {
        // 简化处理，实际应该发送消息通知
        System.out.println("通知管理员审核用户: userId=" + userId);
    }

    /**
     * 生成初始密码
     * @return 初始密码
     */
    private String generateInitialPassword() {
        // 生成8位随机密码
        String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*";
        StringBuilder password = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 8; i++) {
            password.append(chars.charAt(random.nextInt(chars.length())));
        }
        return password.toString();
    }

    /**
     * 发送通知给新管理员
     * @param user 新管理员用户
     * @param initialPassword 初始密码
     */
    private void sendNotificationToNewAdmin(SysUserEntity user, String initialPassword) {
        // 简化处理，实际应该发送邮件或短信
        System.out.println("发送通知给新管理员: username=" + user.getUsername() +
                ", initialPassword=" + initialPassword);
    }
}
